Change Word.dxl to export in table with Colors

Hi,

 

I need to export my module from doors to MS word.. But with a few considerations.

1. I have the attributes values shown in color. especially enumerated attributes. Need to export their values with colors.

2. Change the font size to 8.

3. Set the table size "Fit to contents". So that it does not export half of the table onto another page.

4. Set the header row repeatable  for each page which contains the column names.

5. Define a macro to do all this so cant use LDXL. 

 

I have been looking at word.dxl.  It uses some of the other files as well. But I am unable to find the location where I can put the setting for rich text.

Also I tried the header row option in it set as true., But it doesn't help.

Guidance needed.

Thanks in Advance.


Sadaf - Sun Apr 19 20:09:11 EDT 2015

Re: Change Word.dxl to export in table with Colors
Wolfgang Uhr - Mon Apr 20 05:00:35 EDT 2015

Hi

There is no "setting" for the rich text. The following example was a test to force the colour of a rich text link to be blue:

string sLinkText1 = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1031{\\fonttbl{\\f0\fnil\\fcharset0 Calibri;}}
{\\colortbl ;\\red0\\green0\\blue255;}
\\viewkind4\\uc1\\pard\\sa200\\sl276\\slmult1\\lang7\\f0\\fs22{\\field{\\*\\fldinst{HYPERLINK \"http://www.zf.com\"}}{\\fldrslt{\\ul\\cf1 http://www.zf.com}}}\\f0\\fs22\\par}
"

You have

  • to define a \colortbl
  • to address one of the colors \cf1
  • to be lucky in this sense that there is no bug in doors which destroys your setting

If you want to color your output, you have to parse the rich text string and to insert the rich text data by yourself.

Best regards

Wolfgang

Re: Change Word.dxl to export in table with Colors
Sadaf - Mon Apr 20 17:28:46 EDT 2015

Wolfgang Uhr - Mon Apr 20 05:00:35 EDT 2015

Hi

There is no "setting" for the rich text. The following example was a test to force the colour of a rich text link to be blue:

string sLinkText1 = "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1031{\\fonttbl{\\f0\fnil\\fcharset0 Calibri;}}
{\\colortbl ;\\red0\\green0\\blue255;}
\\viewkind4\\uc1\\pard\\sa200\\sl276\\slmult1\\lang7\\f0\\fs22{\\field{\\*\\fldinst{HYPERLINK \"http://www.zf.com\"}}{\\fldrslt{\\ul\\cf1 http://www.zf.com}}}\\f0\\fs22\\par}
"

You have

  • to define a \colortbl
  • to address one of the colors \cf1
  • to be lucky in this sense that there is no bug in doors which destroys your setting

If you want to color your output, you have to parse the rich text string and to insert the rich text data by yourself.

Best regards

Wolfgang

Thanks for your response Wolfgang,

But, my question still remains, Where to put the rich text code.

I was wondering word.dxl parse and print the columns as "Objects " or "attribute"?

Also say something about the points 2,3,4 and 5.

 

Another question is Can i use the rich text in Edit DXL, to make it usable as a macro or not?

Also I am new to DXL so please help me with the code.

 

Regards,

Sadaf

Re: Change Word.dxl to export in table with Colors
Consultant_DOORS - Mon Apr 20 19:47:50 EDT 2015

When you company wants results, I can help you with this.

Re: Change Word.dxl to export in table with Colors
Wolfgang Uhr - Tue Apr 21 03:13:29 EDT 2015

Sadaf - Mon Apr 20 17:28:46 EDT 2015

Thanks for your response Wolfgang,

But, my question still remains, Where to put the rich text code.

I was wondering word.dxl parse and print the columns as "Objects " or "attribute"?

Also say something about the points 2,3,4 and 5.

 

Another question is Can i use the rich text in Edit DXL, to make it usable as a macro or not?

Also I am new to DXL so please help me with the code.

 

Regards,

Sadaf

Hi Sadaf

Sorry I do not have some code to solve your problem. For my opinion handling colors in doors is tricky, because in some cases the doors edits the color setting of a rich text string itself and overrides your selection.

I cannot say something to word.dxl, because I do not use it. Actually there is or there was no such job on my takslist. And I'm not only a dxl programmer, I've some years experience with visual basic and VBA is a significant part of it. And for me word.dxl is hard to read and hard to use, because this is an VBA interface written by a c or c+ programmer in dxl.

Based on a quick look into this file I would say that you have to integrate your changes in sourceRtf in applyStyleLockPasteInvokeEx. But you should aware that you do not have any dxl-routines to handle richt text manipulations properly. Of course there are some routines which do something with this strings and sometimes it looks useful. But creating a rich text in doors dxl and exporting this by using the clipboard is only a start for a very time consuming developement process if you want to implement additional features.

This routine set http://nrtftree.sourceforge.net/doc/doc030/html/Index.html is a open source for a rich text library in version 0.3. The version number means: Planned was a lot more.

Even this reduced routine set is not availiable in doors dxl. So by chance you can do one or another thing, but you did not have a chance to handle each requirement which is formulated by your client. And "By chance" can mean: Play around some days to find something or not.

So let me go one step behind your questions. Are you shure that you can handle the colour and the font size problem in each rich text string, if you know how to change word.dxl? You have not only the problem to parse the rich text string but to refactor them to your needs. In HTML-Codey you can write <b>t</b><b>e</b><b>s</b><b>t</b> or simple <b>test</b>. Both strings will result in the same output in a browser.

Are you able to refactor all rich text string variants?

So my answer is simple. May be there is a solution for that, but in most caste of this type of requirements, there isn't any one. For me the word.dxl-concept is proved to be wrong.

The only way to come up with a right word document is by using vba-functions directly. But this is not a simple script for placing in a thread like this, this is a little bit of work, because you need word2.dxl.

So in my opionion it makes no sense to think about the questions 2-5. Chances to realize step 1 are very small.

Best regards
Wolfgang

 

Re: Change Word.dxl to export in table with Colors
woodpryan - Tue Apr 21 18:50:20 EDT 2015

Sadaf,

For formatting your table so that rows do not break accross the page, add the following funciton to Word.dxl

You will need to add the cPropertyRos and cPropertyAllowBreakAccrossPages to Ole.inc. A similar stipulation goes for the other functions I give you here.

/*Function:   formatTableNoWidow(OleAutoObj)
  Purpose:    Formats the table to not allow widowing of rows.
  Parameters: the table to be formated.
*/
void formatTableNoWidow(OleAutoObj objTable)
{
    OleAutoObj objRows = null;
    
    if(null != objTable)
    {
        oleGet(objTable, cPropertyRows, objRows);
        if(null != objRows) 
        {
            vbaCheckRes(olePut(objRows, cPropertyAllowBreakAcrossPages, false));
        }
        else
            logError("Unable to acquire rows from table for formatNoWidow");
    }
    else
        logError("Unable to format table noWidow. Table passed as null.");
        
    closeIfNonNull(objRows);
}

For auto fitting the column size, try adding this funciton:

/*  Function:   setTableAllowAutoFit(OleAutoObj, bool)
    Purpose:    sets whether the given table should allow auto fit of columns
    Parameters: the table, whether to allow auto fit
*/
void setTableAllowAutoFit(OleAutoObj objTable, bool bAllow)
{
    if(null == objTable)
    {
        logError("Could not set the Table's AllowAutoFit property because the table was null.");
        return;
    }
    
    olePut(objTable, cPropertyAllowAutoFit, bAllow);
}

For the colors, you're going to need to decide on the colors to use based on some stipulations that have been placed on your program, but the following function will take a Range, retrieve its font, and set that font's color based on the wdColor you pass it. You'll need to call getRange(objCell) on the cell for which you want to change the font color.

/*  Function:   setRangeColor(OleAutoObj, int)
    Purpose:    sets the color of the text in the given range to the given wdColor
    Parameters: the range, the color index as any of wdColorIndex
*/
void setRangeColor(OleAutoObj objRange, int wdColor)
{
    OleAutoObj objFont = null;
    
    if(null == objRange)
    {
        logError("The range passed to setRangeColor was null.");
    }
    
    oleGet(objRange, cPropertyFont, objFont);
    if(null == objFont)
    {
        logError("Could not retrieve the font from the range for setRangeColor.");
        return;
    }
    
    olePut(objFont, cPropertyColorIndex, wdColor);
}

Finally, for setting the table header, add these functions:

/* Function: setRangeAsTableHeader(OleAutoObj)
   Purpose:  sets the range passed as the header of the table
*/
void setRangeAsTableHeader(OleAutoObj objRange)
{
    OleAutoObj objRows = null;
    
    if(null != objRange)
    {
        //first select the range
        oleMethod(objRange, cMethodSelect);
        oleGet(objSel, cPropertyRows, objRows);
        if(null != objRows)
        {
            olePut(objRows, cPropertyHeadingFormat, true);
        }
        else
            logError("Could not get Rows from the Selected Range for setRangeAsTableHeader.");
        closeIfNonNull(objRows);
    }
    else
        logError("Range passed to setRangeAsTableHeader was found null.");
}

/* Function:   getRange(OleAutoObj, int, int, int, int)
   Purpose:    creates a range out of the table from the beginning of the start row/column
               to the end of the end row/column.
   Parameters: The table, the start row, the start column,
               the end row, the end column
   Return:     the range if one was succesfully created. null otherwise
*/
OleAutoObj getRange(OleAutoObj theTable, int sRow, int sCol, int eRow, eCol)
{
    /*The VBA code we need to replicate in DXL
    myTable = ActiveDocument.Tables(1)
    myRange = ActiveDocument.Range(myTable.Cell(1, 1).Range.Start, myTable.Cell(1, 2).Range.End)
    myRange.Cells.Merge
    */
    
    OleAutoObj objRange   = null;
    OleAutoObj objCell    = null;
    OleAutoObj tmpRange   = null;
    int        startRange = 0;
    int        endRange   = 0;
    
    clear(objArgBlock);
    put(objArgBlock, sRow);
    put(objArgBlock, sCol);
    oleMethod(theTable, cMethodCell, objArgBlock, objCell);
    if(null != objCell)
    {
        oleGet(objCell, cPropertyRange, tmpRange);
        if(null!= tmpRange)
        {
            oleGet(tmpRange, cPropertyStart, startRange);
            if(startRange >= 0)
            {
                clear(objArgBlock);
                put(objArgBlock, eRow);
                put(objArgBlock, eCol);
                oleMethod(theTable, cMethodCell, objArgBlock, objCell);
                if(null != objCell)
                {
                    oleGet(objCell, cPropertyRange, tmpRange);
                    if(null != tmpRange)
                    {
                        oleGet(tmpRange, cPropertyEnd, endRange);
                        if(0 != endRange)
                        {
                            clear(objArgBlock);
                            put(objArgBlock, startRange);
                            put(objArgBlock, endRange);
                            oleMethod(objDoc, cMethodRange, objArgBlock, objRange);
                        }
                        else
                            logError("getRange found 0 for endRange.");
                    }
                    else
                        logError("unable to get a tmpRange from the end cell.");
                }
                else
                    logError("objCell is null in getRange.");
            }
            else
                logError("getRange found invalid startRange.");
        }
        else
            logError("Unable to get a tmpRange from the start cell.");
    }
    if(null == objRange)
        logError("Unable to get the specified range!");
        
    closeIfNonNull(tmpRange);
    closeIfNonNull(objCell);
    
    return objRange;
}

You'll need to call getRange on your Table, passing it the start and end row and column as well as the number of rows and columns in the table. Then pass the range to the setRangeAsTableHeader function.

 

Let me know if you have any trouble.

Re: Change Word.dxl to export in table with Colors
Wolfgang Uhr - Wed Apr 22 07:18:45 EDT 2015

woodpryan - Tue Apr 21 18:50:20 EDT 2015

Sadaf,

For formatting your table so that rows do not break accross the page, add the following funciton to Word.dxl

You will need to add the cPropertyRos and cPropertyAllowBreakAccrossPages to Ole.inc. A similar stipulation goes for the other functions I give you here.

/*Function:   formatTableNoWidow(OleAutoObj)
  Purpose:    Formats the table to not allow widowing of rows.
  Parameters: the table to be formated.
*/
void formatTableNoWidow(OleAutoObj objTable)
{
    OleAutoObj objRows = null;
    
    if(null != objTable)
    {
        oleGet(objTable, cPropertyRows, objRows);
        if(null != objRows) 
        {
            vbaCheckRes(olePut(objRows, cPropertyAllowBreakAcrossPages, false));
        }
        else
            logError("Unable to acquire rows from table for formatNoWidow");
    }
    else
        logError("Unable to format table noWidow. Table passed as null.");
        
    closeIfNonNull(objRows);
}

For auto fitting the column size, try adding this funciton:

/*  Function:   setTableAllowAutoFit(OleAutoObj, bool)
    Purpose:    sets whether the given table should allow auto fit of columns
    Parameters: the table, whether to allow auto fit
*/
void setTableAllowAutoFit(OleAutoObj objTable, bool bAllow)
{
    if(null == objTable)
    {
        logError("Could not set the Table's AllowAutoFit property because the table was null.");
        return;
    }
    
    olePut(objTable, cPropertyAllowAutoFit, bAllow);
}

For the colors, you're going to need to decide on the colors to use based on some stipulations that have been placed on your program, but the following function will take a Range, retrieve its font, and set that font's color based on the wdColor you pass it. You'll need to call getRange(objCell) on the cell for which you want to change the font color.

/*  Function:   setRangeColor(OleAutoObj, int)
    Purpose:    sets the color of the text in the given range to the given wdColor
    Parameters: the range, the color index as any of wdColorIndex
*/
void setRangeColor(OleAutoObj objRange, int wdColor)
{
    OleAutoObj objFont = null;
    
    if(null == objRange)
    {
        logError("The range passed to setRangeColor was null.");
    }
    
    oleGet(objRange, cPropertyFont, objFont);
    if(null == objFont)
    {
        logError("Could not retrieve the font from the range for setRangeColor.");
        return;
    }
    
    olePut(objFont, cPropertyColorIndex, wdColor);
}

Finally, for setting the table header, add these functions:

/* Function: setRangeAsTableHeader(OleAutoObj)
   Purpose:  sets the range passed as the header of the table
*/
void setRangeAsTableHeader(OleAutoObj objRange)
{
    OleAutoObj objRows = null;
    
    if(null != objRange)
    {
        //first select the range
        oleMethod(objRange, cMethodSelect);
        oleGet(objSel, cPropertyRows, objRows);
        if(null != objRows)
        {
            olePut(objRows, cPropertyHeadingFormat, true);
        }
        else
            logError("Could not get Rows from the Selected Range for setRangeAsTableHeader.");
        closeIfNonNull(objRows);
    }
    else
        logError("Range passed to setRangeAsTableHeader was found null.");
}

/* Function:   getRange(OleAutoObj, int, int, int, int)
   Purpose:    creates a range out of the table from the beginning of the start row/column
               to the end of the end row/column.
   Parameters: The table, the start row, the start column,
               the end row, the end column
   Return:     the range if one was succesfully created. null otherwise
*/
OleAutoObj getRange(OleAutoObj theTable, int sRow, int sCol, int eRow, eCol)
{
    /*The VBA code we need to replicate in DXL
    myTable = ActiveDocument.Tables(1)
    myRange = ActiveDocument.Range(myTable.Cell(1, 1).Range.Start, myTable.Cell(1, 2).Range.End)
    myRange.Cells.Merge
    */
    
    OleAutoObj objRange   = null;
    OleAutoObj objCell    = null;
    OleAutoObj tmpRange   = null;
    int        startRange = 0;
    int        endRange   = 0;
    
    clear(objArgBlock);
    put(objArgBlock, sRow);
    put(objArgBlock, sCol);
    oleMethod(theTable, cMethodCell, objArgBlock, objCell);
    if(null != objCell)
    {
        oleGet(objCell, cPropertyRange, tmpRange);
        if(null!= tmpRange)
        {
            oleGet(tmpRange, cPropertyStart, startRange);
            if(startRange >= 0)
            {
                clear(objArgBlock);
                put(objArgBlock, eRow);
                put(objArgBlock, eCol);
                oleMethod(theTable, cMethodCell, objArgBlock, objCell);
                if(null != objCell)
                {
                    oleGet(objCell, cPropertyRange, tmpRange);
                    if(null != tmpRange)
                    {
                        oleGet(tmpRange, cPropertyEnd, endRange);
                        if(0 != endRange)
                        {
                            clear(objArgBlock);
                            put(objArgBlock, startRange);
                            put(objArgBlock, endRange);
                            oleMethod(objDoc, cMethodRange, objArgBlock, objRange);
                        }
                        else
                            logError("getRange found 0 for endRange.");
                    }
                    else
                        logError("unable to get a tmpRange from the end cell.");
                }
                else
                    logError("objCell is null in getRange.");
            }
            else
                logError("getRange found invalid startRange.");
        }
        else
            logError("Unable to get a tmpRange from the start cell.");
    }
    if(null == objRange)
        logError("Unable to get the specified range!");
        
    closeIfNonNull(tmpRange);
    closeIfNonNull(objCell);
    
    return objRange;
}

You'll need to call getRange on your Table, passing it the start and end row and column as well as the number of rows and columns in the table. Then pass the range to the setRangeAsTableHeader function.

 

Let me know if you have any trouble.

woodpryan your topic handles excel but the thread topic is word.

Re: Change Word.dxl to export in table with Colors
woodpryan - Wed Apr 22 13:20:31 EDT 2015

Wolfgang Uhr - Wed Apr 22 07:18:45 EDT 2015

woodpryan your topic handles excel but the thread topic is word.

I'm not sure what gave you that impression, but I am positive this code will work for MS Word.

Re: Change Word.dxl to export in table with Colors
Sadaf - Sat May 16 11:39:18 EDT 2015

woodpryan - Wed Apr 22 13:20:31 EDT 2015

I'm not sure what gave you that impression, but I am positive this code will work for MS Word.

Thanks Woodpryan,

 

your functions were really helpful.

Here is two more questions

1.)  I also need to get the font properties of Object Heading (or all the columns).and display it as it Is in Word.

for example,

if an Object Heading says "<b>Section 1.1</b>        The system <b>shall</b> consists of 6 heaters". (section 1.1 and shall in "bold")

2.) I don't understand how to get  range by your function getRange()  and pass to setRange () for Color.

Thanks in advance. waiting for the reply.

 

Regards,

Sadaf

Re: Change Word.dxl to export in table with Colors
woodpryan - Mon May 18 11:55:17 EDT 2015

Sadaf - Sat May 16 11:39:18 EDT 2015

Thanks Woodpryan,

 

your functions were really helpful.

Here is two more questions

1.)  I also need to get the font properties of Object Heading (or all the columns).and display it as it Is in Word.

for example,

if an Object Heading says "<b>Section 1.1</b>        The system <b>shall</b> consists of 6 heaters". (section 1.1 and shall in "bold")

2.) I don't understand how to get  range by your function getRange()  and pass to setRange () for Color.

Thanks in advance. waiting for the reply.

 

Regards,

Sadaf

1. Think of the DXL code in terms of wrapping it around VBA. In the developer tab of your MS Word installation, click the Visual Basic button to bring up the VBA editor. You will find a button to bring up the Object Browser in there. This shows you all the VBA classes, functions, and properties related to MS Word. Let's assume that at the time you want to get the font properties, your cursor (Selection Object) in the document is at the spot where you want to get the information. Let's say you want the font color. The way to get that in VBA is with the following line of code:

l = Selection.Range.Font.Color

Where l is a variable of type Long. What's happening here is we are retrieving the Range class from the Selection, then the Font class from the Range, then the Color property from the Font, and we are storing it in variable l.

Now, you want to translate the VBA code to DXL. DXL provides us a few functions to execute VBA code. Those are oleGet, oleSet, and oleMethod. These functions get a property, set a property, and call a method respectively.

In order to retrieve the color property from the font, get the range from the selection, stored as an oleAutoObject as follows

OleAutoObj objRange = null;

oleGet(objSel, cPropertyRange, objRange);
if(null == objRange)
{
    print("Could not retrieve the Range from the selection for getFont color");
    return;//cannot go further without a range
}

Retrieve the Font and the color similarly. You'll want to store the color in a variable of type int. The color property is an enumeration of type wdColor. You can find all the possible values of wdColor in the Object Browser in your VBA window in your installation of MS Word.

If you need further help with that, let me know.

2. The range. I included a function called getRange, which takes the start and end of the columns and rows. You can use this to get a range from column one through column n, and row 1 through row n. Once you have that range, you can pass it to setRangeAsTableHeader, which will make it appear on every page of the table. the smaller version of getRange, which takes no parameters simply gets a range from the current selection. You can then pass the range to setColor, which takes a range and an integer representation of one of the values of the wdColor enumeration. For example, if you wanted to set the color of the current selection to black:

OleAutoObj objRange = null;

objRange = getRange();
if(null != objRange)
{
    setColor(objRange, wdColorBlack);
    //wdColorBlack is a const int set equal to 0
    //this is the value from wdColor enumeration
    //that represents black.
}

I hope this answers your question and helps you figure out the answer to questions like these in the future. Good luck, my friend. And let me know if you need any clarification here.

Re: Change Word.dxl to export in table with Colors
woodpryan - Mon May 18 12:02:11 EDT 2015

Sadaf - Sat May 16 11:39:18 EDT 2015

Thanks Woodpryan,

 

your functions were really helpful.

Here is two more questions

1.)  I also need to get the font properties of Object Heading (or all the columns).and display it as it Is in Word.

for example,

if an Object Heading says "<b>Section 1.1</b>        The system <b>shall</b> consists of 6 heaters". (section 1.1 and shall in "bold")

2.) I don't understand how to get  range by your function getRange()  and pass to setRange () for Color.

Thanks in advance. waiting for the reply.

 

Regards,

Sadaf

Sorry. Maybe I should have included these functions:

/*  Function:   getRange()
    Purpose:    gets the Range of the current selection.
    Return:     the Range
*/
OleAutoObj getRange()
{
    OleAutoObj objRange = null;
    
    if(null != objSel)
    {
        oleGet(objSel, cPropertyRange, objRange);
    }
    
    return objRange;
}

/*
This function copied directly from word.dxl, provided by DOORS
*/
OleAutoObj getRange(OleAutoObj obj) 
{
    OleAutoObj objRange = null
    
    oleGet(obj,cPropertyRange,objRange);

    return objRange;
}

Getting a Range is one of the things you will need to do most often in interfacing with MS Word. There are all sorts of things you can do with and get from the Range Object.

Re: Change Word.dxl to export in table with Colors
Sadaf - Fri Jul 10 16:56:46 EDT 2015

woodpryan - Mon May 18 12:02:11 EDT 2015

Sorry. Maybe I should have included these functions:

/*  Function:   getRange()
    Purpose:    gets the Range of the current selection.
    Return:     the Range
*/
OleAutoObj getRange()
{
    OleAutoObj objRange = null;
    
    if(null != objSel)
    {
        oleGet(objSel, cPropertyRange, objRange);
    }
    
    return objRange;
}

/*
This function copied directly from word.dxl, provided by DOORS
*/
OleAutoObj getRange(OleAutoObj obj) 
{
    OleAutoObj objRange = null
    
    oleGet(obj,cPropertyRange,objRange);

    return objRange;
}

Getting a Range is one of the things you will need to do most often in interfacing with MS Word. There are all sorts of things you can do with and get from the Range Object.

Hi woodpryan,

 

Thanks for help . I appreciate it.

My code got working most of the things. I have one problem.

When ever I export to word document, It opens two word documents for me. One is empty and the other one contains all the information of exported.

This is strange and at times very annoying.

P.F.A my file, if you can see and point what am I doing wrong.

 

Thanks in Advance

bye

 

 

 


Attachments

Version3.dxl

Re: Change Word.dxl to export in table with Colors
woodpryan - Fri Jul 10 17:09:27 EDT 2015

Sadaf - Fri Jul 10 16:56:46 EDT 2015

Hi woodpryan,

 

Thanks for help . I appreciate it.

My code got working most of the things. I have one problem.

When ever I export to word document, It opens two word documents for me. One is empty and the other one contains all the information of exported.

This is strange and at times very annoying.

P.F.A my file, if you can see and point what am I doing wrong.

 

Thanks in Advance

bye

 

 

 

The reason you end up with two documents is that, on line 984 you call cMethodAdd on objDocs. Then, again, in the same function, you call cMethodAdd on objDocs. This is on line 998. You have several references throughout the rest of the code to one of these documents or the other. The first one is stored in OleAutoObj objDoc. The second is stored in OleAutoObj objDoc2. I hope that helps.